"""New Chat Session & Message API (SSE streaming) - independent from legacy /api/ai/chat."""

from __future__ import annotations

from fastapi import APIRouter, Depends, HTTPException, Query
from fastapi.responses import StreamingResponse
from sqlalchemy.orm import Session
from typing import Optional

from app.database import get_db
from app.utils.auth import get_current_active_user
from app.models.user import User
from app.schemas.chat_session import (
    ChatSessionCreate,
    ChatSessionOut,
    ChatSessionList,
    ChatMessageCreate,
    ChatMessageOut,
    ChatMessageList,
    ChatSessionUpdate,
)
from app.services.chat_session_service import chat_session_service
from app.services.chat_roles import resolve_role_prompt
from app.services.ai_service import ai_service
import re

router = APIRouter(prefix="/chat", tags=["Chat (New)"])


@router.post("/sessions", response_model=ChatSessionOut)
def create_session(
    payload: ChatSessionCreate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_active_user),
):
    session = chat_session_service.create_session(
        db,
        user_id=current_user.id,
        title=payload.title,
        system_prompt=payload.system_prompt,
        model_name=payload.model_name,
        book_id=payload.book_id,
        meta=payload.meta or {},
    )
    return session


@router.get("/sessions", response_model=ChatSessionList)
def list_sessions(
    limit: int = Query(30, ge=1, le=100),
    offset: int = Query(0, ge=0),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_active_user),
):
    sessions, total = chat_session_service.list_sessions(
        db, current_user.id, limit=limit, offset=offset
    )
    return {"sessions": sessions, "total": total}


@router.get("/sessions/{session_id}", response_model=ChatSessionOut)
def get_session(
    session_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_active_user),
):
    session = chat_session_service.get_session(db, session_id, current_user.id)
    if not session:
        raise HTTPException(status_code=404, detail="会话不存在")
    return session


@router.get("/sessions/{session_id}/messages", response_model=ChatMessageList)
def list_messages(
    session_id: int,
    limit: int = Query(50, ge=1, le=200),
    before_seq: Optional[int] = Query(None),
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_active_user),
):
    session = chat_session_service.get_session(db, session_id, current_user.id)
    if not session:
        raise HTTPException(status_code=404, detail="会话不存在")
    msgs, total = chat_session_service.list_messages(
        db, session, limit=limit, before_seq=before_seq
    )
    return {"messages": msgs, "total": total}


@router.post("/sessions/{session_id}/messages")
async def create_message(
    session_id: int,
    payload: ChatMessageCreate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_active_user),
):
    session = chat_session_service.get_session(db, session_id, current_user.id)
    if not session:
        raise HTTPException(status_code=404, detail="会话不存在")
    requested_mode = payload.mode

    # 用户消息
    user_msg = chat_session_service.add_message(
        db,
        session=session,
        user_id=current_user.id,
        role="user",
        content=payload.content,
        is_final=True,
        parent_message_id=payload.parent_message_id,
        model_name=payload.model_name,
        mode_override=requested_mode,
    )

    # 历史 -> 构建对话对
    raw_msgs, _ = chat_session_service.list_messages(db, session, limit=30)
    pairs: list[dict[str, str]] = []
    pending = None
    for m in raw_msgs:
        r = getattr(m, "role", None)
        if r == "user":
            if pending is not None:
                pass
            pending = str(getattr(m, "content", ""))
        elif r == "assistant" and pending is not None:
            pairs.append(
                {"message": pending, "response": str(getattr(m, "content", ""))}
            )
            pending = None
    chat_history = pairs

    if payload.stream is False:
        ai_resp = await ai_service.chat_with_ai(
            message=payload.content,
            book_context=None,
            chat_history=chat_history,
            system_prompt=str(getattr(session, "system_prompt", "") or "") or None,
            summary=str(getattr(session, "summary_compressed", "") or "") or None,
        )
        assistant_msg = chat_session_service.add_message(  # type: ignore[arg-type]
            db,
            session=session,
            user_id=None,
            role="assistant",
            content=ai_resp.get("response", ""),
            is_final=True,
            parent_message_id=user_msg.id,  # type: ignore[arg-type]
            model_name=payload.model_name,
            mode_override=requested_mode,
        )
        fresh = chat_session_service.get_session(db, session_id, current_user.id)
        if fresh and getattr(fresh, "message_count", 0) == 2:
            meta = getattr(fresh, "meta", None) or {}
            allow_auto = (
                not getattr(fresh, "title", None) or str(fresh.title).startswith("会话")
            ) or meta.get("allow_auto_title")
            if allow_auto:
                msgs, _ = chat_session_service.list_messages(db, fresh, limit=4)
                first_user = next(
                    (mm for mm in msgs if getattr(mm, "role", None) == "user"), None
                )
                if first_user:
                    raw = getattr(first_user, "content", "") or ""
                    title_val = await ai_service.generate_title(raw, max_len=12)
                    if title_val:
                        chat_session_service.update_session_title(db, fresh, title_val)
                        meta.pop("allow_auto_title", None)
                        fresh.meta = meta  # type: ignore[assignment]
                        db.commit()
        return {
            "user_message_id": user_msg.id,
            "assistant_message_id": assistant_msg.id,
            "response": ai_resp,
        }

    # 流式：占位消息
    placeholder = chat_session_service.add_message(  # type: ignore[arg-type]
        db,
        session=session,
        user_id=None,
        role="assistant",
        content="",
        is_final=False,
        parent_message_id=user_msg.id,  # type: ignore[arg-type]
        model_name=payload.model_name,
        mode_override=requested_mode,
    )

    async def stream_gen():
        accumulated: list[str] = []
        error: str | None = None
        try:
            async for chunk in ai_service.chat_with_ai_stream(
                message=payload.content,
                book_context=None,
                chat_history=chat_history,
                system_prompt=str(getattr(session, "system_prompt", "") or "") or None,
                summary=str(getattr(session, "summary_compressed", "") or "") or None,
            ):
                if not chunk:
                    continue
                accumulated.append(chunk)
                safe_chunk = chunk.replace("\r", " ")
                yield f"data: {safe_chunk}\n\n"
        except Exception as e:  # noqa
            error = str(e)
            yield f"data: [ERROR]{error}\n\n"
        full = "".join(accumulated)
        chat_session_service.finalize_message(db, placeholder, full)
        fresh = chat_session_service.get_session(db, session_id, current_user.id)
        if fresh and getattr(fresh, "message_count", 0) == 2:
            meta = getattr(fresh, "meta", None) or {}
            allow_auto = (
                not getattr(fresh, "title", None) or str(fresh.title).startswith("会话")
            ) or meta.get("allow_auto_title")
            if allow_auto:
                msgs, _ = chat_session_service.list_messages(db, fresh, limit=4)
                first_user = next(
                    (mm for mm in msgs if getattr(mm, "role", None) == "user"), None
                )
                if first_user:
                    raw = getattr(first_user, "content", "") or ""
                    title_val = await ai_service.generate_title(raw, max_len=12)
                    if title_val:
                        chat_session_service.update_session_title(db, fresh, title_val)
                        meta.pop("allow_auto_title", None)
                        fresh.meta = meta  # type: ignore[assignment]
                        db.commit()
        if not error:
            yield "data: [DONE]\n\n"

    return StreamingResponse(
        stream_gen(), media_type="text/event-stream; charset=utf-8"
    )


# ---------------- Session management extra endpoints ---------------- #


@router.patch("/sessions/{session_id}", response_model=ChatSessionOut)
def update_session(
    session_id: int,
    payload: ChatSessionUpdate,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_active_user),
):
    session = chat_session_service.get_session(db, session_id, current_user.id)
    if not session:
        raise HTTPException(status_code=404, detail="会话不存在")
    # 标题更新
    if payload.title is not None:
        title_trim = payload.title.strip()
        if not title_trim:
            raise HTTPException(status_code=400, detail="标题不能为空")
        if len(title_trim) > 60:
            raise HTTPException(status_code=400, detail="标题过长")
        session = chat_session_service.update_session_title(db, session, title_trim)
    # 角色 / 模式更新：通过 meta.mode 控制
    # ChatSessionUpdate.meta 为 Optional[dict]，这里仅在客户端传入 mode 时才处理
    if payload.meta is not None:
        new_mode = None
        try:
            # 支持直接在 meta 中携带 "mode"
            new_mode = payload.meta.get("mode")  # type: ignore[assignment]
        except Exception:
            new_mode = None
        if new_mode is not None:
            # 合并/更新原有 meta
            current_meta = getattr(session, "meta", None) or {}
            current_meta["mode"] = new_mode
            session.meta = current_meta  # type: ignore[assignment]
            # 根据 mode 选择系统提示词
            preset = resolve_role_prompt(str(new_mode))
            session.system_prompt = preset["system_prompt"]  # type: ignore[assignment]
            db.commit()
            db.refresh(session)
    return session


@router.delete("/sessions/{session_id}")
def delete_session(
    session_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_active_user),
):
    session = chat_session_service.get_session(db, session_id, current_user.id)
    if not session:
        raise HTTPException(status_code=404, detail="会话不存在")
    chat_session_service.delete_session(db, session)
    return {"message": "会话已删除", "session_id": session_id}


@router.delete("/sessions/{session_id}/messages")
def clear_session_messages(
    session_id: int,
    db: Session = Depends(get_db),
    current_user: User = Depends(get_current_active_user),
):
    session = chat_session_service.get_session(db, session_id, current_user.id)
    if not session:
        raise HTTPException(status_code=404, detail="会话不存在")
    deleted = chat_session_service.clear_session(db, session)
    return {"message": "会话历史已清空", "session_id": session_id, "deleted": deleted}
